/**
 * Top.jsx
 * 3D地图顶层组件 - 负责处理地图的顶层交互效果、点击高亮及城市名称展示
 */
import * as THREE from 'three';
import { useRef, useState, useMemo, useCallback } from 'react';
import { Text3D, Html, Edges } from '@react-three/drei';
import { gsap } from 'gsap';

// 材质基础配置
const config = {
	color: '#9cb8e4',  // 基础颜色
	clearcoat: 0.5,    // 清漆效果强度
	reflectivity: 0.35, // 反射率
	ior: 1.3,          // 折射率
};

// 3D文本配置(虽然未使用，但保留以备将来可能启用)
const textConfig = {
	curveSegments: 32,    // 曲线分段数(越高越平滑)
	bevelEnabled: true,   // 启用斜角
	bevelSize: 0,         // 斜角大小
	bevelThickness: 0,    // 斜角厚度
	height: 0.02,         // 文字厚度
	letterSpacing: 0,     // 字间距
	size: 0.25,           // 文字大小
};

// 地图元素缩放比例
const scale = 3.05;

/**
 * 地图顶层组件
 * @param {number} baseHeight - 地图基础高度
 * @param {number} midHeightScale - 中间层高度比例
 * @param {number} topHeightScale - 顶层高度比例
 * @param {Array} blocks - 地图区块数据
 * @param {Object} values - 地图数值数据
 * @param {Array} mapCenter - 地图中心坐标
 * @param {Function} onRegionClick - 区域点击回调，用于获取区域名称
 * @param {Function} onRegionDrillDown - 区域双击回调，用于地图下钻
 * @param {number} distanceFactor - HTML元素缩放因子，控制文本大小
 * @param {number} textYOffset - 文本Y轴偏移量，默认为-0.5
 */
const Top = ({ baseHeight, midHeightScale, topHeightScale, blocks, values, mapCenter, onRegionClick, onRegionDrillDown, distanceFactor = 8, textYOffset = -0.5 }) => {
	// 计算区域排名信息
	let rankInfo = Object.keys(values.features).map((key) => `${key} ${values.features[key]}`);
	rankInfo.sort((a, b) => b.split(' ')[1] - a.split(' ')[1]);  // 按数值降序排序
	rankInfo = rankInfo.map((item, index) => index + 1 + '.' + item);  // 添加排名编号
	
	// 构建区域名称到排名信息的映射
	let rank = {};
	rankInfo.forEach((item) => {
		rank[item.split('.')[1].split(' ')[0]] = item;
	});

	// 区块引用集合，用于动画和交互
	const blocksRef = useRef([]);
	// 区域名称引用集合
	const namesRef = useRef([]);
	// 点击计时器引用
	const clickTimerRef = useRef(null);
	// 记录最后点击的索引，用于判断双击
	const lastClickedIndexRef = useRef(null);

	// 地图标记状态管理
	const [makerVisible, setMakerVisible] = useState(false);  // 标记可见性
	const [makerPosition, setMakerPosition] = useState([0, 2, 0]);  // 标记位置
	const [makerValue, setMakerValue] = useState('');  // 标记显示的值
	// 存储当前选中的区域索引
	const [selectedIndex, setSelectedIndex] = useState(null);

	// 城市名称文本样式
	const cityNameStyle = {
		transition: 'all 0.2s',
		opacity: 1,
		color: '#ffffff',
		fontFamily: 'Consolas',
		fontSize: '34px',
		userSelect: 'none',
		textShadow: '0 0 3px rgba(0,0,0,1)',
		whiteSpace: 'nowrap',
		// 旋转纠正，使文本在3D空间中正常显示
		transform: 'rotate(180deg) rotateY(180deg) rotateX(180deg)'
	};

	/**
	 * 单击事件的具体处理逻辑，在延迟确认不是双击后调用
	 * @param {number} index - 被点击区块的索引
	 */
	const processSingleClick = useCallback((index) => {
		// 获取区域名称
		const regionName = blocks[index].properties.name;
		
		// 判断是否为第二次点击同一区块
		const isSecondClick = blocksRef.current[index].scale.z == 0.8;
		
		// 只在首次点击区域时传递数据，第二次点击同一区域时不传递
		if (!isSecondClick && onRegionClick) {
			onRegionClick(regionName);
		}
		
		// 处理UI交互
		if (isSecondClick) {
			handleSecondClick(index);
		} else {
			handleFirstClick(index);
		}
	}, [blocks, onRegionClick]);

	/**
	 * 区块点击处理函数 - 使用延迟处理避免与双击冲突
	 * @param {Event} e - 点击事件
	 * @param {number} index - 被点击区块的索引
	 */
	const handleClick = (e, index) => {
		e.stopPropagation();  // 阻止事件冒泡
		
		// 清除之前可能存在的点击计时器
		if (clickTimerRef.current !== null) {
			clearTimeout(clickTimerRef.current);
			clickTimerRef.current = null;
		}
		
		// 设置延迟，等待可能的双击事件
		// 延迟时间应小于浏览器的双击检测时间(通常为300ms左右)
		clickTimerRef.current = setTimeout(() => {
			// 延迟结束，确认是单击事件
			clickTimerRef.current = null;
			lastClickedIndexRef.current = null;
			processSingleClick(index);
		}, 250);
		
		// 记录当前点击的索引，用于双击检测
		lastClickedIndexRef.current = index;
	};
	
	/**
	 * 处理第一次点击区块的逻辑
	 * @param {number} index - 被点击区块的索引
	 */
	const handleFirstClick = (index) => {
		// 设置标记(maker)
		const region = blocks[index].properties.name;
		setMakerVisible(true);
		setMakerValue(rank[region]);
		setMakerPosition([
			(blocks[index].properties.center[0] - mapCenter[0]) * scale,
			2,
			-(blocks[index].properties.center[1] - mapCenter[1]) * scale,
		]);
		
		// 更新选中的区域索引
		setSelectedIndex(index);
		
		// 处理之前选中的区块，恢复其状态
		blocksRef.current.forEach((block, lastIndex) => {
			if (block.scale.z === 0.8) {
				// 使用GSAP动画恢复高度
				gsap.to(blocksRef.current[lastIndex].scale, {
					duration: 0.3,
					z: topHeightScale,
				});
				// 恢复默认颜色
				blocksRef.current[lastIndex].material.color = new THREE.Color('#9cb8e4');
				
				// 恢复区域名称显示
				if (namesRef.current[lastIndex]) {
					// 检查是HTML元素还是Three.js对象
					if (namesRef.current[lastIndex].material) {
						// 如果是精灵(方案二)
						namesRef.current[lastIndex].material.opacity = 1;
					} else {
						// 如果是HTML元素(方案一)
						if (namesRef.current[lastIndex].element) {
							namesRef.current[lastIndex].element.style.opacity = 1;
						}
					}
				}
			}
		});
		
		// 突出显示当前选中的区块
		gsap.to(blocksRef.current[index].scale, { duration: 0.3, z: 0.8 });
		blocksRef.current[index].material.color = new THREE.Color('#ffb47e');  // 橙色高亮
		
		// 隐藏当前选中区块的文本
		if (namesRef.current[index]) {
			// 检查是HTML元素还是Three.js对象
			if (namesRef.current[index].material) {
				// 如果是精灵(方案二)
				namesRef.current[index].material.opacity = 0;
			} else {
				// 如果是HTML元素(方案一)
				if (namesRef.current[index].element) {
					namesRef.current[index].element.style.opacity = 0;
				}
			}
		}
	};
	
	/**
	 * 处理第二次点击区块的逻辑(取消选中)
	 * @param {number} index - 被点击区块的索引
	 */
	const handleSecondClick = (index) => {
		// 隐藏标记
		setMakerVisible(false);
		setMakerValue('');
		setMakerPosition([0, 2, 0]);
		
		// 清除选中的区域索引
		setSelectedIndex(null);
		
		// 恢复区块状态
		gsap.to(blocksRef.current[index].scale, {
			duration: 0.3,
			z: topHeightScale,
		});
		blocksRef.current[index].material.color = new THREE.Color('#9cb8e4');
		
		// 恢复区域名称显示
		if (namesRef.current[index]) {
			// 检查是HTML元素还是Three.js对象
			if (namesRef.current[index].material) {
				// 如果是精灵(方案二)
				namesRef.current[index].material.opacity = 1;
			} else {
				// 如果是HTML元素(方案一)
				if (namesRef.current[index].element) {
					namesRef.current[index].element.style.opacity = 1;
				}
			}
		}
	};
	
	/**
	 * 处理双击区块的逻辑(地图下钻)
	 * @param {Event} e - 点击事件
	 * @param {number} index - 被点击区块的索引
	 */
	const handleDoubleClick = (e, index) => {
		e.stopPropagation();  // 阻止事件冒泡
		
		// 清除单击定时器，避免单击操作被触发
		if (clickTimerRef.current !== null) {
			clearTimeout(clickTimerRef.current);
			clickTimerRef.current = null;
		}
		
		// 获取区域名称，用于下钻
		const regionName = blocks[index].properties.name;
		
		// 调用父组件传入的下钻回调函数
		if (onRegionDrillDown) {
			onRegionDrillDown(regionName);
		}
	};
	
	/**
	 * 鼠标悬停在区块上时，将指针样式改为"小手"
	 */
	const handlePointerOver = () => {
		document.body.style.cursor = 'pointer';
	};
	
	/**
	 * 鼠标离开区块时，恢复默认指针样式
	 */
	const handlePointerOut = () => {
		document.body.style.cursor = 'default';
	};
	
	return (
		<>
			
			{/* 城市名称文本组 */}
			<group rotation={[0, Math.PI * 1.1, Math.PI]} position-y={baseHeight + midHeightScale * baseHeight + 0.01}>
				{blocks.map((item, index) => (
					<group key={'city_' + index}>
						<Html
							ref={(el) => {
								namesRef.current[index] = el;
							}}
							position={[
								(item.properties.centroid[0] - mapCenter[0]) * scale,
								textYOffset,
								(item.properties.centroid[1] - mapCenter[1]) * scale,
							]}
							center
							distanceFactor={distanceFactor}
							pointerEvents="none"
							occlude={false}
							style={cityNameStyle}
						>
							<div>{item.properties.name}</div>
						</Html>
					</group>
				))}
			</group>
			
			{/* 城市区块几何体 */}
			<group
				rotation={[-Math.PI * 0.5, 0, Math.PI * 0.09]}
				position-y={baseHeight + midHeightScale * baseHeight + 0.01}
			>
				{blocks.map((item, index) => (
					<group key={'top_' + index}>
						<mesh
							scale={[1, 1, topHeightScale]}
							geometry={blocks[index].children[0].geometry}
							ref={(el) => {
								blocksRef.current[index] = el;
							}}
							onClick={(e) => handleClick(e, index)}
							onDoubleClick={(e) => handleDoubleClick(e, index)}
							onPointerOver={handlePointerOver}
							onPointerOut={handlePointerOut}
						>
							<meshPhysicalMaterial
								{...config}
								transmission={Math.sqrt(
									item.properties.value / Math.max(...Object.values(values.features))
								)}
								roughness={Math.sqrt(
									item.properties.value / Math.max(...Object.values(values.features))
								)}
							/>
							<Edges color={'#ffffff'} />
						</mesh>
					</group>
				))}
			</group>
		</>
	);
};

export default Top;
